package com.remoteapp.networking;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetSocketAddress;
import java.net.Socket;

public class Client implements Runnable {

	/** Only one socket because only one client allowed */
	private Socket socket = null;

	/** Writer for the socket */
	private BufferedWriter writer = null;
	/** Reader for the socket */
	private BufferedReader reader = null;

	/** Receiver to notify connection actions */
	private ClientReceiver receiver = null;

	/**
	 * Constructor. The client connects to the given IP and port
	 * 
	 * @param ipAddress
	 *            The IP address to connect to
	 * @param port
	 *            The port to connect to
	 * @throws Exception
	 *             Is thrown when something went wrong with the connection
	 */
	public Client(String ipAddress, int port) throws Exception {

		// Create connection
		socket = new Socket();
		socket.connect(new InetSocketAddress(ipAddress, port), 1500);

		// Initialize reader and writer
		writer = new BufferedWriter(new OutputStreamWriter(
				socket.getOutputStream()));
		reader = new BufferedReader(new InputStreamReader(
				socket.getInputStream()));
	}

	/**
	 * Constructor. The client connects to the given IP and port and sets the
	 * receiver for the actions
	 * 
	 * @param ipAddress
	 *            The IP address to connect to
	 * @param port
	 *            The port to connect to
	 * @param recv
	 *            The receiver to notify the connection actions
	 * @throws Exception
	 *             Is thrown when something went wrong with the connection
	 */
	public Client(String ipAddress, int port, ClientReceiver recv)
			throws Exception {

		// Create connection
		socket = new Socket(ipAddress, port);
		receiver = recv;

		// Initialize reader and writer
		writer = new BufferedWriter(new OutputStreamWriter(
				socket.getOutputStream()));
		reader = new BufferedReader(new InputStreamReader(
				socket.getInputStream()));
	}

	/**
	 * @return The IP address to the connected server. If no connection
	 *         available, an empty string is returned
	 */
	public String getIPAdress() {
		if (socket == null) {
			return "";
		}

		return socket.getLocalAddress().getHostAddress();
	}

	/**
	 * Disconnects the client from the server closing the socket
	 * 
	 * @throws IOException
	 *             Is thrown when socket can not be closed
	 */
	public void disconnect() throws IOException {
		receiver = null;
		socket.close();
	}

	/**
	 * Sends a message via the socket of this client
	 * 
	 * @param msg
	 *            The given message to send
	 * @throws IOException
	 *             Is thrown when the writing causes error
	 */
	public void sendMessage(String msg) throws IOException {
		writer.write(msg);
		writer.newLine();
		writer.flush();
	}

	@Override
	public void run() {
		try {
			while (socket.isBound()) {
				String line = reader.readLine();

				// Check received line
				if (line != null) {

					if (receiver != null) {
						receiver.lineReceived(line);
					}
				} else {
					break;
				}
			}

			if (receiver != null) {
				receiver.disconnectedFromServer(socket.getInetAddress()
						.getHostAddress());
			}

		} catch (Exception e) {

			if (receiver != null) {
				receiver.lostConnection(socket.getInetAddress()
						.getHostAddress());
			}
		}
	}

}
